3.05. Теория данных
Разработчику
Аналитику
Тестировщику
Архитектору
Инженеру
Теория данных
1. Основы теории информатики в части данных
Теория данных вытекает из более общей теории информации, предложенной Клодом Шенноном, и из теории вычислимости, развитой Алонзо Чёрчем, Алланом Тьюрингом и другими. Однако в контексте информационных систем данные рассматриваются не как энтропийные величины, а как структурированные объекты, подлежащие манипуляции в рамках строго определённых моделей.
Ключевое понятие — данные как представление знаний. Любая система хранения данных предполагает наличие модели, определяющей:
- какие типы данных допустимы;
- как данные связаны между собой;
- как над ними могут быть выполнены операции;
- как обеспечивается целостность и согласованность.
В теории информатики данные формализуются через понятие реляции (в рамках реляционной модели), графа (в графовых базах), документа (в документ-ориентированных системах) или ключа-значения (в key-value хранилищах). Эти модели не являются взаимоисключающими — они отражают различные уровни абстракции и подходы к организации информации в зависимости от требований приложения.
Наиболее строго и формально развита реляционная модель данных, предложенная Эдгаром Коддом в 1970 году. Она базируется на теории множеств и логике предикатов первого порядка и до сих пор остаётся основой для большинства промышленных СУБД.
2. Как работает база данных и СУБД на самом низшем уровне
Система управления базами данных (СУБД) — это программный комплекс, предоставляющий интерфейс для хранения, извлечения, модификации и управления данными с гарантией их целостности, безопасности и производительности. На самом низком уровне СУБД — это набор алгоритмов и структур данных, которые взаимодействуют с операционной системой и, через неё, с аппаратными ресурсами вычислительной машины.
Основные компоненты СУБД на уровне реализации:
- Менеджер буферов (Buffer Manager) — отвечает за перемещение данных между оперативной памятью и диском.
- Менеджер дискового пространства (Storage Manager) — управляет физическим расположением данных на диске, включая файлы, страницы и блоки.
- Менеджер транзакций (Transaction Manager) — обеспечивает ACID-свойства (атомарность, согласованность, изолированность, долговечность).
- Менеджер выполнения запросов (Query Execution Engine) — преобразует логические операции (например,
SELECT) в последовательность физических действий над данными. - Оптимизатор запросов (Query Optimizer) — выбирает наиболее эффективный план выполнения запроса на основе статистики и стоимости операций.
На аппаратном уровне данные хранятся в виде последовательностей байтов на энергонезависимом носителе — традиционно на жёстком диске (HDD) или твердотельном накопителе (SSD). СУБД не работает напрямую с оборудованием, а использует системные вызовы операционной системы (read, write, mmap и др.) для доступа к файлам базы данных.
3. Где хранятся данные (на диске)
Физическое хранение данных в реляционной СУБД обычно организовано по принципу страничной структуры. База данных представляет собой один или несколько файлов, разделённых на фиксированные блоки — страницы (pages), типичный размер которых составляет 4 КБ, 8 КБ или 16 КБ, в зависимости от СУБД (например, PostgreSQL использует 8 КБ, Microsoft SQL Server — 8 КБ по умолчанию).
Каждая страница содержит:
- заголовок (метаданные: тип страницы, идентификатор отношения, контрольные суммы и т.п.);
- тело — фрагменты записей (tuples или rows);
- иногда — слот-массив, указывающий смещения записей внутри страницы.
Записи (rows) не обязательно хранятся последовательно — они могут фрагментироваться, особенно при обновлении переменной длины. Для поддержки целостности и быстрого доступа используется индексная структура, чаще всего — сбалансированное дерево (B+ дерево), которое также хранится на диске в виде страниц.
Важно понимать: диск — это иерархический, последовательный по природе носитель. Даже в SSD, где отсутствует механический seek, эффективность чтения/записи зависит от выравнивания блоков и внутренней архитектуры контроллера NAND-памяти. Поэтому СУБД стремятся минимизировать количество случайных обращений и максимизировать локальность данных.
4. Как СУБД работает с диском
Когда приходит SQL-запрос, например SELECT * FROM users WHERE id = 100, СУБД не читает всю таблицу с диска целиком. Вместо этого она:
- Анализирует запрос и строит его логическое представление (предикаты, соединения и т.п.).
- Оптимизатор выбирает план выполнения — например, использовать индекс по полю
id. - Менеджер выполнения инициирует чтение нужных страниц с диска через менеджер буферов.
- Менеджер буферов проверяет, есть ли запрашиваемая страница в оперативной памяти (в буферном пуле). Если нет — выполняется системный вызов для чтения с диска.
- Прочитанная страница кэшируется в памяти, чтобы последующие запросы к тем же данным не требовали повторного обращения к диску.
Таким образом, работа с диском происходит лениво и выборочно: только те страницы, которые действительно нужны для выполнения запроса, загружаются в память. Это критически важно, поскольку объём данных на диске может значительно превышать объём оперативной памяти.
СУБД также использует запись журналов (Write-Ahead Logging, WAL): перед тем как изменить данные на диске, СУБД записывает изменения в специальный лог (журнал транзакций), что позволяет восстановить согласованное состояние после сбоя.
5. Почему базы данных предпочтительнее хранения в ОЗУ
Хранение данных исключительно в оперативной памяти (in-memory) возможно и используется в специализированных системах (например, Redis, MemSQL). Однако классические СУБД с дисковым хранением обладают рядом фундаментальных преимуществ:
- Долговечность (Durability): данные сохраняются после выключения питания или аварийного завершения работы. ОЗУ — энергозависимый ресурс.
- Масштабируемость по объёму: объём диска измеряется терабайтами и петабайтами, тогда как ОЗУ ограничено физическими и экономическими рамками.
- Контроль целостности: СУБД реализует сложные механизмы (ограничения, внешние ключи, триггеры, ACID), которые невозможно или нецелесообразно воспроизводить вручную в пользовательском коде.
- Конкуренция и изоляция: СУБД управляет параллельным доступом множества клиентов к данным, обеспечивая корректность через механизмы блокировок, MVCC (многоверсионного управления конкурентным доступом) и т.д.
- Оптимизированная работа с носителем: СУБД знают структуру данных и могут эффективно использовать индексы, кластеризацию, сжатие и предвыборку (prefetching), что недоступно при простом хранении в памяти.
In-memory хранилища — это частный случай, оправданный при строгих требованиях к задержке, но они не заменяют дисковые СУБД в общем случае.
6. Реляционная алгебра и реляционное исчисление
Реляционная модель данных, предложенная Эдгаром Коддом, покоится на двух формальных основаниях: реляционной алгебре и реляционном исчислении. Эти две системы не дублируют друг друга, а скорее дополняют: первая ориентирована на как вычислять результат, вторая — на что должно быть в результате.
Реляционная алгебра — это процедурный формализм. Она состоит из набора операторов, которые принимают одно или несколько отношений (таблиц) и возвращают новое отношение. Основные операторы включают:
- Выборку (selection) — фильтрация строк по условию;
- Проекцию (projection) — выбор подмножества столбцов;
- Декартово произведение — комбинирование всех строк двух отношений;
- Соединение (join) — комбинирование строк с учётом условия соответствия;
- Объединение, пересечение и разность — теоретико-множественные операции над совместимыми по структуре отношениями;
- Переименование атрибутов — изменение имён столбцов без изменения содержания.
Каждая операция алгебры строго определена и всегда возвращает корректное отношение. Это позволяет строить планы выполнения запросов как последовательности этих операций. Именно реляционная алгебра лежит в основе внутреннего представления SQL-запросов в большинстве СУБД: парсер SQL преобразует запрос в древовидную структуру, соответствующую выражению реляционной алгебры, которое затем оптимизируется и исполняется.
Реляционное исчисление, в свою очередь, основано на логике предикатов первого порядка. Оно позволяет формулировать запросы в декларативной форме: указывается, какие кортежи должны присутствовать в результате, через логические условия, которым они должны удовлетворять. Например, «найти все строки, для которых существует запись в другой таблице с таким же идентификатором». В отличие от алгебры, здесь не задаётся последовательность шагов — только условие результата.
Ключевой теоретический результат — эквивалентность реляционной алгебры и реляционного исчисления в выразительной силе. Это означает, что любой запрос, выразимый в одной системе, может быть выражен и в другой. Более того, Кодд ввёл понятие реляционной полноты: СУБД считается реляционно полной, если она способна реализовать все операции реляционной алгебры. SQL, несмотря на некоторые отклонения от чистой теории (например, допускает дубликаты строк и отсутствие полной поддержки всех свойств отношений), в своей основе соответствует этому требованию.
Эти формальные основы обеспечивают предсказуемость и корректность обработки данных. Пользователь описывает что ему нужно, а СУБД берёт на себя задачу как это получить, используя мощный аппарат оптимизации на основе алгебраических преобразований и статистики данных.
7. Как вычисляются связи на низком уровне
Термин «связи» в контексте баз данных чаще всего относится к внешним ключам (foreign keys) — ограничениям целостности, устанавливающим, что значение в одном столбце (или наборе столбцов) одной таблицы должно соответствовать значению первичного ключа в другой таблице.
На логическом уровне это выглядит как декларативное правило: «значение столбца user_id в таблице orders должно существовать в столбце id таблицы `users». Однако на физическом уровне реализация этого правила требует конкретных механизмов.
Проверка внешнего ключа выполняется СУБД в момент модификации данных:
- При вставке строки в дочернюю таблицу (
orders) СУБД ищет соответствующую запись в родительской таблице (users). Это поиск по индексу первичного ключа — операция, в большинстве случаев логарифмическая по времени. - При удалении или обновлении строки в родительской таблице СУБД проверяет, ссылаются ли на неё какие-либо строки в дочерних таблицах. В зависимости от политики (например,
CASCADE,RESTRICT,SET NULL) могут быть выполнены дополнительные действия.
Важно: сами связи не хранятся как отдельные объекты на диске. Нет «ссылок» в том смысле, в каком они существуют в памяти (например, указатели). Связь — это логическое ограничение, реализуемое через:
- наличие индексов по столбцам внешнего и первичного ключей (для эффективного поиска);
- выполнение проверок при операциях изменения данных;
- поддержание согласованности при восстановлении после сбоев (через WAL-журналы).
При выполнении операции соединения (JOIN) СУБД физически комбинирует строки из двух таблиц, сопоставляя значения в соответствующих столбцах. Существует несколько алгоритмов соединения:
- Вложенные циклы (nested loops) — для каждой строки из левой таблицы просматриваются все строки правой;
- Соединение по хешу (hash join) — строится хеш-таблица по одной таблице, затем вторая таблица сканируется и сверяется по хешу;
- Сортировка и слияние (sort-merge join) — обе таблицы сортируются по ключу соединения, затем выполняется линейное слияние.
Выбор алгоритма зависит от объёма данных, наличия индексов, доступной памяти и статистики распределения значений. Все эти алгоритмы оперируют страницами данных, загружаемыми в буферный пул, и стремятся минимизировать количество операций ввода-вывода.
Таким образом, связи в реляционной модели — это не физические указатели, а логические зависимости, поддерживаемые через индексы, алгоритмы соединения и механизмы контроля целостности, реализованные на уровне СУБД.